﻿using Authority.Doamin;
using Authority.Doamin.IRepository;
using Authority.Doamin.View;
using HelperFromTheSkeleton.EFBaseRepository;
using Microsoft.EntityFrameworkCore;
using System.Data;
using System.Linq.Expressions;

namespace Authority.EFRepositoryImpl.EFRepositoryImpl
{
    public class UserRepositoryImpl : EFBaseRepositoryImpl<User>, IUserRepository
    {
        private readonly AuthorityDbContext _authorityDbContext;
        public UserRepositoryImpl(AuthorityDbContext authorityDbContext) : base(authorityDbContext)
        {
            _authorityDbContext = authorityDbContext;
        }

        /// <summary>
        /// 查找用户角色信息视图
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<List<UserRoleInfoView>> FindUserRoleInfoViewAsync(Expression<Func<User, bool>> expression)
        {
            var userRoleDbSet = _authorityDbContext.UserRoleAuthority;
            var roleDbSet = _authorityDbContext.RoleAuthority;
            var dbInfo = await (from user in _dbSet.Where(expression)
                                join userRole in userRoleDbSet on user.ID equals userRole.UserID into userRoles
                                from userRoleDE in userRoles.DefaultIfEmpty()
                                join role in roleDbSet on userRoleDE.RoleAuthorityID equals role.ID into roleRoles
                                from roleDE in roleRoles.DefaultIfEmpty()
                                select new
                                {
                                    user.ID,
                                    user.Name,
                                    user.DateUpTime,
                                    user.WeCathOpenID,
                                    user.IsDelete,
                                    user.AccountNumber,
                                    user.Password,
                                    user.DateAddTime,
                                    RoleID = roleDE==null?null:(Guid?)roleDE.ID,
                                    RoleName = roleDE==null?null:roleDE.Name,
                                    RoleCode = roleDE==null?null:roleDE.Code,
                                    RoleParentID = roleDE==null?null:roleDE.ParentID,
                                }).ToListAsync();
            var dbInfoOrderByUserID = dbInfo.GroupBy(m => m.ID).ToList();
            var result = new List<UserRoleInfoView>();
            dbInfoOrderByUserID.ForEach(m =>
            {
                var user = m.FirstOrDefault();
                if (user == null) return;
                UserRoleInfoView userView = new()
                {
                    AccountNumber = user.AccountNumber,
                    DateAddTime = user.DateAddTime,
                    DateUpTime = user.DateUpTime,
                    ID = user.ID,
                    IsDelete = user.IsDelete,
                    Name = user.Name,
                    Password = user.Password,
                    WeCathOpenID = user.WeCathOpenID,
                    RoleInfos = m.Where(m=>m.RoleID!=null).GroupBy(m => m.RoleID).Select(n =>
                    {
                        var role = n.FirstOrDefault();
                        return new RoleView
                        {
                            ID = role?.RoleID ?? Guid.Empty,
                            Code = role?.RoleCode ?? "",
                            Name = role?.RoleName ?? "",
                            ParentID = role?.RoleParentID ?? Guid.Empty,
                        };
                    }).ToList(),
                };
                result.Add(userView);
            });
            return result;
        }

        /// <summary>
        /// 查找用户菜单信息视图
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<List<UserMenuInfoView>> FindUserMenuInfoViewAsync(Expression<Func<User, bool>> userExpression, Expression<Func<MenuAuthority, bool>> menuExpression)
        {
            var userRoleDbSet = _authorityDbContext.UserRoleAuthority;
            var roleDbSet = _authorityDbContext.RoleAuthority;
            var roleMenuDbSet = _authorityDbContext.RoleAuthorityMenu;
            var menuDbSet = _authorityDbContext.MenuAuthority.Where(menuExpression);
            var routingDbSet = _authorityDbContext.RoutingAuthority;
            var dbInfo = await (from user in _dbSet.Where(userExpression)
                                join userRole in userRoleDbSet on user.ID equals userRole.UserID into userRoles
                                from userRoleDE in userRoles.DefaultIfEmpty()
                                join role in roleDbSet on userRoleDE.RoleAuthorityID equals role.ID into roleRoles
                                from roleDE in roleRoles.DefaultIfEmpty()
                                join roleMenu in roleMenuDbSet on roleDE.ID equals roleMenu.RoleAuthorityID into roleMenuRoles
                                from roleMenuDE in roleMenuRoles.DefaultIfEmpty()
                                join menu in menuDbSet on roleMenuDE.MenuAuthorityID equals menu.ID into menus
                                from menuDE in menus.DefaultIfEmpty()
                                join routing in routingDbSet on menuDE.RoutingAuthorityID equals routing.ID into routingRoutings
                                from routingDE in routingRoutings.DefaultIfEmpty()
                                select new
                                {
                                    user.ID,
                                    user.Name,
                                    user.DateUpTime,
                                    user.WeCathOpenID,
                                    user.IsDelete,
                                    user.AccountNumber,
                                    user.Password,
                                    user.DateAddTime,
                                    MenuID = menuDE==null?null: (Guid?)menuDE.ID,
                                    MenuName = menuDE == null ? null : menuDE.Name,//menuDE.Name,
                                    MenuCode = menuDE == null ? null : menuDE.Name,// menuDE.Name,
                                    MenuAddress = routingDE == null ? null : routingDE.Address,// routingDE.Address,
                                    MenuSubsystemID = menuDE == null ? null : (Guid?)menuDE.SubsystemID,//menuDE.SubsystemID,
                                    MenuParentID = menuDE == null ? null : menuDE.ParentID//menuDE.ParentID
                                }).ToListAsync();
            var dbInfoOrderByUserID = dbInfo.GroupBy(m => m.ID).ToList();
            var result = new List<UserMenuInfoView>();
            dbInfoOrderByUserID.ForEach(m =>
            {
                var user = m.FirstOrDefault();
                if (user == null) return;
                UserMenuInfoView userView = new()
                {
                    AccountNumber = user.AccountNumber,
                    DateAddTime = user.DateAddTime,
                    DateUpTime = user.DateUpTime,
                    ID = user.ID,
                    IsDelete = user.IsDelete,
                    Name = user.Name,
                    Password = user.Password,
                    WeCathOpenID = user.WeCathOpenID,
                    MenuInfos = m.Where(m => m.MenuID != null).GroupBy(m => m.MenuID).Select(m =>
                    {
                        var menu = m.FirstOrDefault();
                        return new MenuView
                        {
                            ID = menu?.MenuID ?? Guid.Empty,
                            Name = menu?.MenuName ?? "",
                            Code = menu?.MenuCode ?? "",
                            ParentID = menu?.MenuParentID,
                            SubsystemID = menu?.MenuSubsystemID ?? Guid.Empty,
                            Routing = menu?.MenuAddress ?? ""
                        };
                    }).ToList()
                };
                result.Add(userView);
            });
            return result;
        }

        /// <summary>
        /// 查找用户功能信息视图
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<List<UserActionInfoView>> FindUserActionInfoViewAsync(Expression<Func<User, bool>> userExpression, Expression<Func<ActionAuthority, bool>> actionExpression)
        {
            var userRoleDbSet = _authorityDbContext.UserRoleAuthority;
            var roleDbSet = _authorityDbContext.RoleAuthority;
            var roleActionDbSet = _authorityDbContext.RoleAuthorityAction;
            var actionDbSet = _authorityDbContext.ActionAuthority.Where(actionExpression);
            var dbInfo = await (from user in _dbSet.Where(userExpression)
                                join userRole in userRoleDbSet on user.ID equals userRole.UserID into userRoles
                                from userRoleDE in userRoles.DefaultIfEmpty()
                                join role in roleDbSet on userRoleDE.RoleAuthorityID equals role.ID into roleRoles
                                from roleDE in roleRoles.DefaultIfEmpty()
                                join roleAction in roleActionDbSet on roleDE.ID equals roleAction.RoleAuthorityID into roleActions
                                from roleActionDE in roleActions.DefaultIfEmpty()
                                join action in actionDbSet on roleActionDE.ActionAuthorityID equals action.ID into actions
                                from actionDE in actions.DefaultIfEmpty()
                                select new
                                {
                                    user.ID,
                                    user.Name,
                                    user.DateUpTime,
                                    user.WeCathOpenID,
                                    user.IsDelete,
                                    user.AccountNumber,
                                    user.Password,
                                    user.DateAddTime,
                                    ActionID = actionDE == null?null:(Guid?)actionDE.ID,
                                    ActionName = actionDE == null ? null : actionDE.Name,//actionDE.Name,
                                    ActionCode = actionDE == null ? null : actionDE.Code,//actionDE.Code,
                                    ActionSubsystemID = actionDE == null ? null : (Guid?)actionDE.SubsystemID//actionDE.SubsystemID
                                }).ToListAsync();
            var dbInfoOrderByUserID = dbInfo.GroupBy(m => m.ID).ToList();
            var result = new List<UserActionInfoView>();
            dbInfoOrderByUserID.ForEach(m =>
            {
                var user = m.FirstOrDefault();
                if (user == null) return;
                UserActionInfoView userView = new()
                {
                    AccountNumber = user.AccountNumber,
                    DateAddTime = user.DateAddTime,
                    DateUpTime = user.DateUpTime,
                    ID = user.ID,
                    IsDelete = user.IsDelete,
                    Name = user.Name,
                    Password = user.Password,
                    WeCathOpenID = user.WeCathOpenID,
                    ActionInfo = m.Where(m => m.ActionID != null).GroupBy(m => m.ActionID??Guid.Empty).ToDictionary(m => m.Key, m =>
                    {
                        var action = m.FirstOrDefault();
                        return (action?.ActionName ?? "", action?.ActionCode ?? "", action?.ActionSubsystemID ?? Guid.Empty);
                    })
                };
                result.Add(userView);
            });
            return result;
        }

        /// <summary>
        /// 查找用户路由信息视图
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<List<UserRoutingView>> FindUserRoutingViewAsync(Expression<Func<User, bool>> userExpression, Expression<Func<RoutingAuthority, bool>> routingExpression)
        {
            var userRoleDbSet = _authorityDbContext.UserRoleAuthority;
            var roleDbSet = _authorityDbContext.RoleAuthority;
            var roleRoutingDbSet = _authorityDbContext.RoleAuthorityRouting;
            var routingDbSet = _authorityDbContext.RoutingAuthority.Where(routingExpression);
            var dbInfo = await (from user in _dbSet.Where(userExpression)
                                join userRole in userRoleDbSet on user.ID equals userRole.UserID into userRoles
                                from userRoleDE in userRoles.DefaultIfEmpty()
                                join role in roleDbSet on userRoleDE.RoleAuthorityID equals role.ID into roleRoles
                                from roleDE in roleRoles.DefaultIfEmpty()
                                join roleRouting in roleRoutingDbSet on roleDE.ID equals roleRouting.RoleAuthorityID into roleRoutings
                                from roleRoutingDE in roleRoutings.DefaultIfEmpty()
                                join routing in routingDbSet on roleRoutingDE.RoutingAuthorityID equals routing.ID into routings
                                from routingsDE in routings.DefaultIfEmpty()
                                select new
                                {
                                    user.ID,
                                    user.Name,
                                    user.DateUpTime,
                                    user.WeCathOpenID,
                                    user.IsDelete,
                                    user.AccountNumber,
                                    user.Password,
                                    user.DateAddTime,
                                    RoutingsID = routingsDE==null?null:(Guid?)routingsDE.ID,
                                    RoutingsName = routingsDE == null ? null : routingsDE.Name,
                                    RoutingsCode = routingsDE == null ? null : routingsDE.Code,
                                    RoutingSubsystemID = routingsDE == null ? null : (Guid?)routingsDE.SubsystemID,
                                    RoutingParentID = routingsDE == null ? null : routingsDE.ParentID,
                                    RoutingAccress = routingsDE == null ? null : routingsDE.Address
                                }).ToListAsync();
            var dbInfoOrderByUserID = dbInfo.GroupBy(m => m.ID).ToList();
            var result = new List<UserRoutingView>();
            dbInfoOrderByUserID.ForEach(m =>
            {
                var user = m.FirstOrDefault();
                if (user == null) return;
                UserRoutingView userView = new()
                {
                    AccountNumber = user.AccountNumber,
                    DateAddTime = user.DateAddTime,
                    DateUpTime = user.DateUpTime,
                    ID = user.ID,
                    IsDelete = user.IsDelete,
                    Name = user.Name,
                    Password = user.Password,
                    WeCathOpenID = user.WeCathOpenID,
                    RoutingsInfos = m.Where(m => m.RoutingsID != null).GroupBy(m => m.RoutingsID).Select(m =>
                    {
                        var routing = m.FirstOrDefault();
                        return new RoutingView
                        {
                            ID = routing?.RoutingsID ?? Guid.Empty,
                            Name = routing?.RoutingsName ?? "",
                            Code = routing?.RoutingsCode ?? "",
                            ParentID = routing?.RoutingParentID,
                            SubsystemID = routing?.RoutingSubsystemID ?? Guid.Empty,
                            Address = routing?.RoutingAccress ?? ""
                        };
                    }).ToList()
                };
                result.Add(userView);
            });
            return result;
        }
    }
}
